#include "ssd2828.h"
#include <stdio.h>

//#include "ST7703__BV055HDE_N47_3Q00.h"

void Delay_spi(void)
{
    volatile uint32_t i, j;

    i = 0xff;
    while (i--)
    {
        j++;
        __NOP();
    }
}

void spi_init(void)
{
    SET_CS();
    CLR_SDA();
    CLR_CLK();
}

void spi_bit(uint8_t sda)
{
    if (sda != 0)
    {
        SET_SDA();
    }
    else
    {
        CLR_SDA();
    }
    Delay_spi();

    SET_CLK();
    Delay_spi();

    CLR_CLK();
}

void spi_byte(uint8_t data)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        spi_bit((data << i) & 0x80);
    }
}

uint8_t spi_read(void)
{
    uint8_t rdT = 0x00;
    for (uint8_t kk = 0; kk < 8; kk++)
    {
        rdT = rdT << 1;
        SET_CLK();
        Delay_spi();

        if (getMISO())
        {
            rdT |= 0x01;
        }
        CLR_CLK();
        Delay_spi();
    }

    return rdT;
}

/*void spi_write(uint8_t cod, uint8_t data)
{
    CLR_CS();
    spi_bit(cod);
    spi_byte(data);
    SET_CS();
}*/

void ssd2828_writeReg(uint8_t addr, uint8_t data15_8, uint8_t data7_0)
{
    CLR_CS();

    spi_bit(0);
    spi_byte(addr);

    spi_bit(1);
    spi_byte(data7_0);

    spi_bit(1);
    spi_byte(data15_8);

    SET_CS();
}

uint16_t ssd2828_readReg(uint8_t reg)
{
    uint8_t rdT;
    uint16_t reValue;

    CLR_CS();
    Delay_spi();

    spi_bit(0);
    spi_byte(reg);

    spi_bit(0);
    spi_byte(0xfa);

    rdT = spi_read();

    reValue = rdT;

    rdT = spi_read();

    reValue += (rdT << 8);

    SET_CS();
    Delay_spi();

    return reValue;
}

//void spi_writeMulti()

void ssd2828_dsiWriteMulti_A(uint8_t format, uint16_t len, uint8_t *array)
{
    sendFormat(format, len);

    for (uint16_t i = 0; i < len; i++)
    {
        W_D(array[i]);
    }
}

void ssd2828_dsiWriteMulti_B(uint8_t format, uint8_t *array)
{
    sendFormat(format, array[0]);

    for (uint16_t i = 1; i < array[0]; i++)
    {
        W_D(array[i]);
    }
}

void Write_Byte(u8 num)
{
    u8 count;
    for (count = 0; count < 8; count++)
    {
        if (num & 0x80)
            SET_SDA();
        else
            CLR_SDA();
        Delay_spi();

        SET_CLK();

        num <<= 1;
        Delay_spi();

        CLR_CLK();
        //Delay_spi();
    }
}

void W_C(u8 CMD)
{
    CLR_CLK();
    CLR_CS();
    Delay_spi();

    CLR_SDA();
    Delay_spi(); //BIT8(D/C)=0 REG

    SET_CLK();
    Delay_spi();

    CLR_CLK();
    Delay_spi();

    Write_Byte(CMD);

    SET_CS();
    Delay_spi();
}

void W_D(u8 DAT)
{
    CLR_CLK();
    CLR_CS();
    Delay_spi();

    SET_SDA();
    Delay_spi(); //BIT8(D/C)=0 REG

    SET_CLK();
    Delay_spi();

    CLR_CLK();
    Delay_spi();

    Write_Byte(DAT);

    SET_CS();
    Delay_spi();
}

void GP_COMMAD_PA(u16 a)
{
    W_C(0xBC);
    W_D(a);
    W_D(a >> 8);
    W_C(0xBF);
}

void sendFormat(u8 format, u16 len)
{
    //LCD driver initialization
    W_C(0xB7);
    if (format)
    {              //DCS
        W_D(0x50); //10=TX_CLK 30=PCLK
    }
    else
    {              //GEN
        W_D(0x10); //10=TX_CLK 30=PCLK
    }
    W_D(0x02);

    W_C(0xBD);
    W_D(0x00);
    W_D(0x00);

    W_C(0xBC);
    W_D(len);
    W_D(len >> 8);
    W_C(0xBF);
}

void testSendFormat(void)
{
    /*while(1){
    
    //13 gen 1p
    //sendFormat(GEN, 1); 
    //W_D(0xB1);
    
    //23 gen 2p
    //sendFormat(GEN, 2); 
    //W_D(0xB0);W_D(0x04);
       
    //29 gen long
    //sendFormat(GEN, 3); 
    //W_D(0xB1);W_D(0xB1);W_D(0xB1);
    
    
    
    //05 dcs 0p
    //sendFormat(DCS, 1); 
    //W_D(0x11);
    
    //15 dcs 1p
    //sendFormat(DCS, 2); 
    //W_D(0x11);W_D(0x29);
        
    //39 dcs long
    sendFormat(DCS, 3); 
    W_D(0x11);W_D(0x29);W_D(0x10);
  }*/
}

U16 SPI_READ_REG(U8 reg)
{
    U8 /*cmd, */ rdT;
    U16 reValue;
    //U32 kk;

    CLR_CS();
    Delay_spi();
    /*
    CLR_SDA(); //Set DC=0, for writing to Command register
    Delay_spi();
    CLR_CLK();
    Delay_spi();
    SET_CLK();
    Delay_spi();
    */

    spi_bit(0);

    /*cmd = reg;
    CLR_CLK();
    Delay_spi();
    for (kk = 0; kk < 8; kk++)
    {
        if ((cmd & 0x80) == 0x80)
        {
            SET_SDA();
            Delay_spi();
        }
        else
        {
            CLR_SDA();
            Delay_spi();
        }
        SET_CLK();
        Delay_spi();
        CLR_CLK();
        Delay_spi();
        cmd = cmd << 1;
    }*/
    spi_byte(reg);

    /*CLR_SDA();
    Delay_spi(); //Set DC=0, for writing to Command register
    CLR_CLK();
    Delay_spi();
    SET_CLK();
    Delay_spi();*/
    spi_bit(0);

    /*cmd = 0xFA;
    CLR_CLK();
    Delay_spi();
    for (kk = 0; kk < 8; kk++)
    {
        if ((cmd & 0x80) == 0x80)
        {
            SET_SDA();
            Delay_spi();
        }
        else
        {
            CLR_SDA();
            Delay_spi();
        }
        SET_CLK();
        Delay_spi();
        CLR_CLK();
        Delay_spi();
        cmd = cmd << 1;
    }*/
    spi_byte(0xfa);

    /*rdT = 0;
    for (kk = 0; kk < 8; kk++)
    {
        rdT = rdT << 1;
        SET_CLK();
        Delay_spi();
        
        
        if (getMISO())
        {
            rdT |= 0x01;
        }
        CLR_CLK();
        Delay_spi();
    }*/
    rdT = spi_read();

    reValue = rdT;
    //reValue = (reValue<<8)&0xFF00;

    /*rdT = 0;
    for (kk = 0; kk < 8; kk++)
    {
        rdT = rdT << 1;
        SET_CLK();
        Delay_spi();


        if (getMISO())
        {
            rdT |= 0x01;
        }
        CLR_CLK();
        Delay_spi();
    }
*/
    rdT = spi_read();

    reValue += (rdT << 8);

    SET_CS();
    Delay_spi();

    return reValue;
}

void Wr_com_data16(U8 c, U16 value)
{
    CLR_CS();
    W_C(c);
    W_D(value & 0xff);
    W_D((value >> 8) & 0xff);
    SET_CS();
}

void ssd2828_readID(void)
{
    printf("ssd2828_readID\r\n");
    int a;
    Wr_com_data16(0xd4, 0x00FA);
    a = SPI_READ_REG(0xb0);
    if (a == 0x2828)
    {
        printf(" \r\n");
        printf("The SSD2828 ID: 0x%x  ^-^  successful !! \r\n", a);
        printf(" \r\n");
    }
    else
    {
        printf(" \r\n");
        printf("The SSD2828 ID: 0x%x  -_-! failing !!!! \r\n", a);
        printf(" \r\n");
    }
}

void readMipi(U8 type, U8 lpclk, U8 returnLen, U8 mipiSlaveRegAddr, U16 *returnData)
{
    U16 data0xC6, i;
    U8 /*cmd, */ rdT;
    U16 reValue;
    U32 kk;

    do
    {
        //---------------------SETP1---------------------
        // Send 0xB7 0x82, 0x03 e.g. LP generic read
        //W_C(0xb7); W_D(0x82); W_D(0x03); //generic read
        W_C(0xb7);

        switch (type)
        {
        case DCS:
            W_D(0xC2);
            break;

        case GEN:
            W_D(0x82);
            break;

        default:
            break;
        }
        W_D(0x03); // DCS read

        // Send 0xBB 0xXX, 0x00 "XX" is the register for LP freq. setting Rx internal clock freq. must be similar to Tx
        W_C(0xBB);
        W_D(lpclk);
        W_D(0x00);
        // Send 0xC1 0x0A, 0x00 Max. return packet is 255 bytes
        W_C(0xC1);
        W_D(returnLen);
        W_D(0x00);
        // Send 0xC0 0x00, 0x01
        W_C(0xC0);
        W_D(0x00);
        W_D(0x01);
        // Send 0xBC 0x01, 0x00
        W_C(0xBC);
        W_D(0x01);
        W_D(0x00);
        // Send 0xBF 0xXX, 0x00 "XX" is the register of display driver
        W_C(0xBF);
        W_D(mipiSlaveRegAddr);
        W_D(0x00);

        //MIPI Read

        // check 0xC6 bit 0, aka RDR register, Read Data Ready
        // Preparation for 0xFF read
        // Send 0xD4 0xFA, 0x00 Set read command "FA" for 3 wire 8bit
        W_C(0xD4);
        W_D(0xFA);
        W_D(0x00);
        // Send C6h, with DC bit =0 Read register 0xC6
        // Send 0xFA, with DC bit =0 "FA" read command
        // Read data from SDO Data [7:0] Confirm bit0 is "1
        // Read data from SDO Data [15:8]
        //data0xC6 = SPI_READ_REG(0xC6);
        data0xC6 = SPI_READ_REG(0xb0);
        printf("0xC6 = 0x%x\r\n", data0xC6);
        //UART1_Printf("0xC6\r\n");
        //UART1_SendData8(0xC6);
        HAL_Delay(1);
    } while ((data0xC6 & 0x0001) == 0);

    //---------------------SETP2---------------------
    // loop to read data
    // Send FFh, with DC bit =0
    W_C(0xFF);
    for (i = 0; i < returnLen; i++)
    {
        // Send 0xFA, with DC bit =0
        W_C(0xFA);

        //CLR_CLK();
        CLR_CLK();
        Delay_spi();
        //LCD_CS_CLR;
        CLR_CS();
        Delay_spi();
        // Read data from SDO Data [7:0]
        rdT = 0;
        for (kk = 0; kk < 8; kk++)
        {
            rdT = rdT << 1;
            //SET_CLK();
            SET_CLK();
            Delay_spi();
            //if(GPIO_ReadInputPin(/*PD3*/ GPIOD, GPIO_PIN_3)){
            if (getMISO())
            {
                rdT |= 0x01;
            }
            CLR_CLK();
            Delay_spi();
        }
        reValue = rdT;

        // Read data from SDO Data [15:8]
        rdT = 0;
        for (kk = 0; kk < 8; kk++)
        {
            rdT = rdT << 1;
            //SET_CLK();
            SET_CLK();
            Delay_spi();
            //if(GPIO_ReadInputPin(/*PD3*/ GPIOD, GPIO_PIN_3)){
            if (getMISO())
            {
                rdT |= 0x01;
            }
            CLR_CLK();
            Delay_spi();
        }

        reValue += (rdT << 8);

        returnData[i] = reValue;
        //SET_CS();
        SET_CS();
        Delay_spi();
    }
}

void ssd2828_hwreset(void)
{
    SET_RST();
    delay_ms(100); //(Min 10mS)

    CLR_RST();     //Reset Signal generate
    delay_ms(100); //(Min 10mS)

    SET_RST();
    delay_ms(100);
}
